<?php

namespace magein\think\command;

use magein\think\command\traits\CommandParamParse;
use magein\utils\Variable;
use think\console\Command;
use think\console\Input;
use think\console\input\Argument as InputArgument;
use think\console\input\Option;
use think\console\Output;

class MakeModel extends Command
{

    use CommandParamParse;

    protected string $help = '
    
    支持数据库表名称缩写,匹配到多个可以用-i 参数进行选择
    
    php think model:new users                      创建model/User.php
    php think model:new user_orders                创建model/UserOrder.php
    php think model:new user_orders -r             创建model/user/UserOrder.php
    php think model:new user_orders --validate --service --docs
    php think model:new user -a                    创建验证文件,创建服务,创建文档
    php think model:new u -i 1 -a                  u是表名称缩写,将会列表以u开头的表
';

    protected function configure()
    {
        // 指令配置
        $this->setName('model:new')
            ->setDescription('快速生成模型')
            ->addArgument('table_name', InputArgument::REQUIRED, '数据库表名称')
            ->addOption('recursion', 'r', Option::VALUE_NONE, '生成递归文件目录')
            ->addOption('docs', '', Option::VALUE_NONE, '生成docs')
            ->addOption('validate', '', Option::VALUE_NONE, '生成validate')
            ->addOption('service', '', Option::VALUE_NONE, '生成service')
            ->addOption('all', 'a', Option::VALUE_NONE, '生成service,validate')
            ->addOption('index', 'i', Option::VALUE_OPTIONAL, '选择索引编号')
            ->setHelp($this->help);
    }

    protected function execute(Input $input, Output $output)
    {

        if (\think\facade\Env::get('app_env') !== 'local') {
            $output->error('只能在开发环境中使用');
            exit();
        }

        $table_name = $input->getArgument('table_name');
        $recursion = $input->getOption('recursion');
        $validate = $input->getOption('validate');
        $service = $input->getOption('service');
        $docs = $input->getOption('docs');
        $all = $input->getOption('all');
        $index = $input->getOption('index') ?: 0;

        if ($all) {
            $validate = true;
            $service = true;
            $docs = true;
        }

        $result = $this->tableAttrs($table_name, intval($index));

        if ($result->getCode()) {
            $output->error($result->getMsg());
            return false;
        }

        $table_info = $result->getData();
        $table_name = $table_info['table_name'];
        $attrs = $table_info['attrs'];

        $config = $this->app->config->get('console.config.model', []);

        // 基本路径
        $base_path = $config['path'] ?? '' ?: 'app/model';

        if ($recursion === false) {
            $recursion = $config['recursion'] ?? false;
        }


        if ($recursion) {
            $name = $table_name;
            $params = explode('_', $name);
            if (count($params) > 1) {
                $base_path .= '/' . $params[0];
            }
        }

        if (!is_dir($base_path) && !mkdir($base_path, 0777, true)) {
            $output->error("创建模型目录失败{$base_path}，请先创建该目录");
            exit(1);
        }

        $base_path = trim(trim($base_path, '.'), '/');
        $namespace = str_replace('/', '\\', $base_path);

        $class_name = Variable::pascal($table_name);
        $filename = $base_path . '/' . $class_name . '.php';

        $uses = [];

        $const = '';

        $traits = [];

        $trans = [];

        if ($attrs) {
            foreach ($attrs as $attr) {
                $field = $attr['Field'];
                $type = $attr['Type'];
                $comment = $attr['Comment'];
                if (str_contains($type, 'tinyint')) {

                    $comments = explode(' ', $comment);

                    /**
                     * 过滤空格(注意0值)
                     */
                    $comments = array_filter($comments, function ($value) {
                        if ($value === '') {
                            return false;
                        }
                        return true;
                    });

                    $is_status = false;
                    if (str_contains($comment, 'forbid')) {
                        $is_status = true;
                    }

                    if ($field === 'status' && count($comments) === 7 && $is_status) {
                        $uses[] = 'magein\think\utils\translate\StatusTranslate';
                        $traits[] = 'use StatusTranslate;';
                    } elseif ($field == 'sex') {
                        $uses[] = 'magein\think\utils\translate\SexTranslate';
                        $traits[] = 'use SexTranslate;';
                    } elseif ($field == 'gender') {
                        $uses[] = 'magein\think\utils\translate\GenderTranslate';
                        $traits[] = 'use GenderTranslate;';
                    } else {

                        $desc = $comments[0];

                        array_shift($comments);

                        /**
                         * 是否是三的倍数
                         */
                        $normal = count($comments) % 3;
                        if ($normal === 0) {

                            $comments = array_chunk($comments, 3);
                            foreach ($comments as $comment) {
                                $second = $comment[1];
                                $v = $comment[0];
                                //拼接常量
                                $format = sprintf('%s_%s', strtoupper($field), strtoupper($comment[2]));
                                $const .= <<<EOF

    /**
     * $desc:$second
     */
    const $format = $v;
 
EOF;

                                $trans[$field][] = [$format, $second];
                            }
                        }
                    }
                }
            }
        }

        $extends = $config['extends'] ?? '';
        if ($extends) {
            $uses[] = $extends;
            $extends = explode('\\', $extends);
            $extends = end($extends);
        } else {
            $uses[] = 'think\Model';
            $extends = 'Model';
        }

        if (is_file($filename)) {
            $output->error('file exists:' . $filename);
            exit();
        }

        $trait_string = '';
        foreach ($traits as $trait) {
            $trait_string .= $trait . "\n";
        }

        $use_string = '';
        foreach ($uses as $use) {
            $use_string .= 'use ' . $use . ";\n";
        }

        $trans_string = '';
        foreach ($trans as $key => $value) {

            $f = Variable::pascal($key);

            $options = "";
            foreach ($value as $val) {
                $options .= sprintf('            self::%s => \'%s\',', $val[0], $val[1]) . "\n";
            }
            $options = substr($options, 0, strlen($options) - 2);

            // 拼接转化
            $trans_string .= <<<EOF

    
    /**
     * @param string|int|null \$value
     * @return string|array
     */
    public static function translate{$f}(int|string \$value = null): array|string
    {
        \$data = [
$options
        ];

        if (\$value !== null) {
            return \$data[\$value] ?? '';
        }

        return \$data;
    }
    
    /**
     * @param \$value
     * @return int
     */
    public function set{$f}Attr(\$value): int
    {
        return intval(\$value);
    }
    
    /**
     * @param \$value
     * @param \$data
     * @return string
     */
    public function get{$f}TextAttr(\$value, \$data): string
    {
        \$value = \$value ?: (\$data['$key'] ?? '');
        if (\$value === '' || \$value === null) {
            return '';
        }

        return self::translate{$f}(\$value);
    }

EOF;
        }

        $content = <<<EOF
<?php

namespace $namespace;

$use_string

class {$class_name} extends $extends
{
    
    protected \$table = '$table_name';
    
    $trait_string
    
    $const
    $trans_string
}
EOF;

        file_put_contents($filename, $content);

        $output->writeln('make model successful');

        \think\facade\Console::call('model:attr');

        if ($validate) {
            \think\facade\Console::call('model:vi', [$table_name]);
        }

        if ($service) {
            \think\facade\Console::call('model:service', [$table_name]);
        }

        if ($docs) {
            \think\facade\Console::call('model:docs', [$table_name]);
        }
    }
}
